﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using UMC.Data;
using UMC.Net;
using UMC.Web;
using UMC.Security;
using UMC.Proxy.Entities;
using System.Collections;

namespace UMC.Proxy
{

    [Mapping(Weight = 0, Desc = "云模块服务组件")]
    public class WebFactory : IWebFactory
    {
        internal static Dictionary<String, Dictionary<String, WebAuthType>> Auths = new Dictionary<string, Dictionary<string, WebAuthType>>();

        class XHRActivity : WebActivity
        {
            public XHRActivity(SiteConfig site)
            {
                this.site = site;

            }
            SiteConfig site;
            public override void ProcessActivity(WebRequest request, WebResponse response)
            {
                var user = this.Context.Token.Identity();
                var httpProxy = new HttpProxy(site, this.Context.Client.Context, -1, false, "/");
                if (httpProxy.Domain == null)
                {
                    this.Prompt("安全审记", $"此应用临时关闭，请联系应用管理员");
                }
                switch (site.Site.UserModel)
                {
                    case UserModel.Bridge:
                        break;
                    default:
                        this.Prompt("UMC云模块只支持权限桥接模式");
                        break;
                }

                if (Auths.TryGetValue(site.Root, out var _dic) == false)
                {
                    _dic = new Dictionary<string, WebAuthType>();
                    new Uri(httpProxy.Domain, "/UMC/System/Setup/Mapping").WebRequest().Get(r =>
                    {
                        r.ReadAsString(js =>
                        {
                            var ds = JSON.Deserialize(js) as Hashtable;

                            if (ds?.ContainsKey("data") == true)
                            {
                                var data = ds["data"] as Array;
                                foreach (var o in data)
                                {
                                    var dic = o as Hashtable;
                                    if (dic.ContainsKey("model"))
                                    {
                                        var model = dic["model"] as string;
                                        var auth = dic["auth"] as string;
                                        WebAuthType authType = WebAuthType.All;
                                        switch (auth)
                                        {
                                            case "all":
                                                continue;
                                            case "admin":
                                                authType = WebAuthType.Admin;
                                                break;
                                            case "guest":
                                                authType = WebAuthType.Guest;
                                                break;
                                            case "user":
                                                authType = WebAuthType.User;
                                                break;
                                            case "usercheck":
                                                authType = WebAuthType.UserCheck;
                                                break;
                                            case "check":
                                                authType = WebAuthType.Check;
                                                break;
                                        }
                                        if (dic.ContainsKey("cmd"))
                                        {
                                            _dic[$"{model}.{dic["cmd"]}"] = authType;
                                        }
                                        else
                                        {
                                            _dic[model] = authType;
                                        }
                                    }

                                }
                                Auths[site.Root] = _dic;
                            }


                        }, e => { });

                    });

                }
                if (this.Context.Items.Contains(typeof(WebFactory)) == false)
                {
                    if (site.Site.IsAuth == true)
                    {
                        if (WebClient.Verify(httpProxy.Account, site.Site.SiteKey.Value, request.Model, request.Command, _dic) == false)
                        {
                            if (!user.IsAuthenticated)
                                this.Context.Send("Login", false);
                            this.Prompt("访问此云模块受限");
                        }
                    }
                    else
                    {
                        if (WebClient.Verify(user, 0, request.Model, request.Command, _dic) == false)
                        {
                            if (!user.IsAuthenticated)
                                this.Context.Send("Login", false);
                            this.Prompt("访问此云模块受限");
                        }
                    }
                    this.Context.Items[typeof(WebFactory)] = true;
                }

                StringBuilder sb = new StringBuilder();
                sb.Append("_model=");
                sb.Append(request.Model);
                sb.Append("&_cmd=");
                sb.Append(request.Command);
                var sv = request.SendValues;
                if (sv != null)
                {
                    var em = sv.GetDictionary().GetEnumerator();
                    while (em.MoveNext())
                    {
                        sb.Append("&");
                        sb.Append(Uri.EscapeDataString(em.Key.ToString()));
                        sb.Append("=");
                        sb.Append(Uri.EscapeDataString(em.Value.ToString()));

                    }
                }
                var values = request.Headers.GetDictionary()[request.Command];
                if (values is string)
                {
                    sb.Append("&_=");
                    sb.Append(Uri.EscapeDataString(values as string));


                }
                else if (values is string[])
                {
                    var stv = values as string[];
                    if (stv.Length > 0)
                    {
                        sb.Append("&__=");
                        sb.Append(Uri.EscapeDataString(String.Join('/', stv)));
                    }
                }
                httpProxy.AuthBridge();
                var query = request.Url.Query ?? "";
                if (query.StartsWith("?_v="))
                {
                    int v = query.IndexOf('&');
                    if (v > 0)
                    {
                        query = query.Substring(0, v);
                    }
                }
                var getUrl = new Uri(httpProxy.Domain, $"/UMC/{Utility.Guid(this.Context.Token.Device.Value)}/{query}");
                var content = this.Context.Client.Context;

                var webReq = httpProxy.Reqesut(content.Transfer(getUrl, httpProxy.Cookies));
                webReq.ContentType = "application/x-www-form-urlencoded";
                webReq.Post(sb.ToString(), res =>
                {
                    int StatusCode = (int)res.StatusCode;

                    if (StatusCode > 300 && StatusCode < 400)
                    {
                        httpProxy.ProcessEnd();
                        var url = res.Headers.Get("Location");

                        response.Redirect(new Uri(content.Url, url));

                        this.Context.OutputFinish();
                    }
                    else
                    {
                        res.ReadAsString(xhr =>
                        {
                            httpProxy.ProcessEnd();
                            String eventPfx = "{\"ClientEvent\":";
                            if (xhr.StartsWith(eventPfx))
                            {
                                var xData = JSON.Deserialize(xhr) as Hashtable;

                                var webEvent = (WebEvent)Utility.Parse(xData["ClientEvent"].ToString(), 0);

                                response.ClientEvent = webEvent;
                                if (xData.ContainsKey("Headers"))
                                {
                                    var header = xData["Headers"] as Hashtable;
                                    var m = header.GetEnumerator();
                                    while (m.MoveNext())
                                    {
                                        response.Headers.Put(m.Key as string, m.Value);
                                    }
                                }
                                if (xData.ContainsKey("Redirect"))
                                {
                                    var redirect = xData["Redirect"] as Hashtable;
                                    var model = redirect["model"] as string;
                                    var cmd = redirect["cmd"] as string;
                                    if (String.IsNullOrEmpty(model) == false && String.IsNullOrEmpty(cmd) == false)
                                    {
                                        var send = redirect["send"];
                                        if (send is IDictionary)
                                        {
                                            response.Redirect(model, cmd, new WebMeta(send as IDictionary), false);
                                        }
                                        else if (send is string)
                                        {

                                            response.Redirect(model, cmd, send as string, false);
                                        }
                                        else
                                        {
                                            response.Redirect(model, cmd, false);
                                        }
                                    }

                                }

                            }
                            else
                            {
                                response.Headers.Put("Data", Data.JSON.Expression(xhr));
                                response.ClientEvent |= (WebEvent)131072;
                            }

                            this.Context.OutputFinish();
                        }, error =>
                        {
                            if (error is WebAbortException)
                            {
                                this.Context.OutputFinish();
                            }
                            else
                            {
                                this.Context.Client.Context.Error(error);
                            }
                        });
                    }
                });
                response.Redirect(Empty);

            }
        }
        class XHRFlow : WebFlow
        {
            public override WebActivity GetFirstActivity()
            {
                var m = this.Context.Request.Model;
                var cmd = this.Context.Request.Command;

                var cgf = Data.Reflection.Configuration("UMC");
                var p = cgf[$"{m}.{cmd}"] ?? cgf[$"{m}.*"];
                if (p != null)
                {
                    var root = p.Attributes["root"];
                    if (String.IsNullOrEmpty(root) == false)
                    {
                        var site = DataFactory.Instance().SiteConfig(p.Attributes["root"]);
                        if (site != null)
                            return new XHRActivity(site);
                    }

                }

                return WebActivity.Empty;

            }
        }
        public virtual WebFlow GetFlowHandler(string mode)
        {
            return new XHRFlow();
        }
        /// <summary>
        /// 请在此方法中完成url与model的注册,即调用registerModel方法
        /// </summary>
        /// <param name="context"></param>
        public virtual void OnInit(WebContext context)
        {

        }
    }
}

